查看原文
其他

设计模式系列(开篇):啥是设计模式?

一航 一行Java 2022-08-09

设计模式系列1

大家好,我是mbb。

前端时间,花了一段时间去整理并开发了一个用于刷面试题的小程序;整理各种资料,耗费了比较多的时间,虽然还有更多的资料需要整理,决定暂时换个方式,缓解缓解,来整理一下设计模式系列。


都说天下武功,无坚不摧,唯快不破!不仅武林中适用这个法则,编程、写代码同样也不例外;

能快速开发需求,能及时应对bug,能轻松搞定调整,你自然就能升值加薪,担任总经理,出任CEO,赢取白富美,走向人生巅峰。

那如何才能快呢?武林高手几乎个个都是内力深厚;那程序员的内力该如何修炼呢?我觉得,「设计模式」就是其中的一本盖世神功的武功秘籍;

接下来的一段时间,会围绕着设计模式展开一个系列的文章,来好好梳理一下这块儿;

整体会围绕下面这张图的各个点展开:

设计模式系列

什么是设计模式

「设计模式」(Design Pattern)是前辈们对「代码开发经验的总结」,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性可维护性可读性稳健性以及安全性的解决方案。

通俗点说,就是前人栽树,后人乘凉!你现在遇到的坑已经早就被别人踩过并且给解决了,解决完之后,他们还将经验教训总结并分享了出来;你需要做的就是,将这些经验学会,并且运用到实际的开发中,那么你的盖世绝学就算是练成了。

《Design Patterns: Elements of Reusable Object-Oriented Software》(《设计模式》)),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。共收录了「23 种设计模式」;这几位作者常被称为"「四人组」(Gang of Four)",而这本书也就被称为"四人组(或 GoF)"书。       -----来源于【百度百科】

什么样的代码才是优秀的呢?

  • 「复用性强」

    「明天上线」”我想是开发人员经常会听到的一个“成语”;我们不能一味的怪产品经理、领导为难我们;很多时候,商场如战场,机会、商机稍纵即逝;因此就得争分夺秒的在第一时间将产品推出来;

    那作为开发人员,如何去应对这种压力呢?

    可以将之前已经写过的代码复用起来,减少不必要的重复工作,让我们能专心去面对业务层面的开发。代码的复用,觉得可以分为以下几个层面

    • 「类的复用」

      比如特定的工具类,大小写转换啦,文件读写啦!都可以整理成工具类库;快速使用,减少不必要的开发;

    • 「设计模式的运用」

      熟练的运用设计模式,将业务抽象,将功能抽离,让其更具备扩展性和复用性;

    • 「框架」

      将某个特定的模块,以框架的形式抽离,让他独立起来;然后从中暴露特定的类;使用方可以通过这些暴露的类,去与这些框架建立联系并使用其中的功能。

  • 「扩展性强」

    你为什么会讨厌需要变更?

    产品的迭代,总是会经历一个过程,没有谁会一开始就将产品的细节想的清清楚楚,所以,产品需要的更新迭代是必然会经历的一个过程;那到底是什么让你那么不爽呢?最重要的一个原因就是改动太大;如果每个需求的调整,你只需要添加一个方法、或者添加一个类就能解决了,那你会不开心吗?你不会!

    所以优秀开发写的代码是具有很强的扩展性,从一开始就运用设计模式埋下了未来可能出现的扩展点,来应付将来可能出现的产品调整;这样,就算将来有一天真的需要改,也就能从容不迫的去面对。

什么影响着设计模式的学习?

  1. 「太难了」

    设计模式更多的是偏理论,在学习的过程中;经常会有种错觉,貌似理论看明白了,但是真正上手去写,发现就无从下手。遇到这个问题,归根究底,还是没有悟透,还差点火候。

  2. 「没啥用?」

    我又不是架构师,我学那玩儿有啥用?

    我不会设计模式,好像正常的业务开发也没啥影响呢!

    其实日常的开发中,「我们几乎无时无刻都在用设计模式」,不管是用其他人的框架,还是自己的业务代码;很多时候只是我们没有留意或者没有意识到这就是设计模式;

    哪怕是一段比较烂的代码,其中可能也用到了某些设计模式,只是没有用好而已。

    所以,不要认为,只有架构师才需要学这个;学好设计模式,不管是对你日常开发、开始框架搭建,都会起到至关重要的作用;再说,就算你现在不是架构师,将来你也要成为架构师的撒。

设计模式的分类

23种设计模式 + 简单工厂

GoF 23种设计模式 + 简单工厂模式
  • 按目的划分

    • 「创建型」

      用来描述“如何创建一个对象”;就是说将对象的创建过程和使用过程分离开来;GoF设计模式中的创建型:单例模式原型模式工厂方法模式抽象工厂模式建造者模式;外加简单工厂模式

    • 「结构型」

      如何将类、对象按一定要求、规则构建成一个更大、有组织的结构体;便于更方便的使用;GoF设计模式中的结构型:代理模式适配器模式桥接模式装饰器模式外观模式享元模式组合模式

    • 「行为型」

      用来组织、描述类或对象之间的相互协作、责任划分;共同来完成单个对象无法完成的事情;GoF设计模式中的行为型:模板方法模式策略模式命令模式责任链模式状态模式观察者模式中介者模式迭代器模式访问者模式备忘录模式解释器模式

  • 按作用范围划分

    • 作用于「类」

      用于确认类与子类之间的关系,这种关系是通过继承建立的,是一种静态的关系,在代码编译的时候,就已经确认了这种关系;工厂方法、(类)适配器、模板方法、解释器属于该类型的模式;

    • 作用于「对象」

      用于组织对象之间的关系,通过组合或聚合,去完成单个类无法完成的任务,这个组合过程,在运行的过程中是允许变化的,因此具有一定的动态性;除了上面说到的四种模式,其他的都属于该类型的模式。

各个模式的功能

这里简单的介绍一下每个模式的作用;后续会对每一个模式以单独的文章再展开详细的介绍。

  • 「单例模式(Singleton)」

    确保一个类在一个进程中只会存在一个实例;该类会提供一个方法作为全局的访问点,来供使用方获取对应的实例;

  • 「原型模式(Prototype)」

    将一个对象作为原型,通过复制的方式,克隆出多个和目标实例类似的新实例;

  • 「简单工厂模式(Simple Factory)」

    定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类

  • 「工厂方法模式(Factory Method)」

    定义一个具体功能相关的接口,由子类来决定这么实现;可以理解为,定义一个行业标准,具体以什么样的方式生成商品我不管,由你各自的工厂自行决定;最后生成出来的产品,符合我的规范即可。

  • 「抽象工厂模式(Abstract Factory)」

    提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。

  • 「建造者模式(Builder)」

    将一个复杂实例的创建过程拆解成多个小的步骤,然后在真正实例化对象的时候,按照需要,拼接各个需要的步骤并组成一个复杂的对象;

  • 「代理模式(Proxy)」

    为实例对象提供一个代理对象,用来控制对目标对象的访问;调用方访问的是代理对象的方法,再由代理对象去访问目标对象的具体方法;因为有代理对象的存在,就可以通过代理对象对目标对象进行校验、控制、调整等操作;

  • 「适配器模式(Adapter Class/Object)」

    将一个类的接口,通过适配器,转换成另外一个接口,从而实现两个不相关的接口之间能够协调工作;比如:美版的iphone充电头不能在国内的插板上面充电,就可以在网上买个转换头,转换一下,就可以正常充电了。

  • 「桥接模式(Bridge)」

    将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

  • 「装饰器模式(Decorator)」

    为对象动态的添加一些职责,从而添加一些额外的功能;就好比游戏中的装备,一个角色代表一个对象,各个部位的装备(头盔、护甲、披风、鞋子、腰带等)都是附加的装饰,并且能添加一个额外的加成;就可以通过装饰者模式来完成;

  • 「外观模式(Facade)」

    为多个复杂的子类提供一个一致的接口,以方便调用方使用;

  • 「享元模式(Flyweight)」

    通过共享的方式来完成大量细粒度的对象的复用;来提高系统的可复用性;

  • 「组合模式(Composite)」

    将对象的组合成树状结构,使使用者对单个对象或多个对象的访问具有一致性;

  • 「模板方法模式(Template Method)」

    对外提供一个业务执行流程的骨架方法,骨架方法中定义了业务抽象出来的执行顺序、操作方式;而具体方法的实现,就下放到各个子列去根据实际的业务需求进行实现;调用方调用的是骨架方法,代码会根据骨架方法中指定的顺序,以此调用子类中的实现,完成业务;

  • 「策略模式(Strategy)」

    定义一系列的算法,并将这些算法给封装起来,保证他们具有可替换性,当遇到不同的常见,替换不同的算法,而不影响用户的使用;比如网站的背景图片,不同的节日,有不同的背景,我们可以将不同的节日定义一种策略,并指定对应节日的背景图;调用方使用的使用,发现今天是圣诞节,那就使用圣诞节的策略返回;如果是元旦节,就是用元旦节的策略返回。

  • 「命令模式(Command)」

    将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。

  • 「责任链模式(Chain of Responsibility)」

    把请求从链中的一个对象传到下一个对象,直到请求被响应为止;通过这种方式去除对象之间的耦合。典型的案例就是企业OA系统的审批,当没有权限审批的时候,就交由上级领导审批,直到由审批权限的领导为止;

  • 「状态模式(State)」

    允许一个对象在其内部状态发生改变时改变其行为能力。

  • 「观察者模式(Observer)」

    当对象出现一对多的关系时,当一个对象发生变化时,会主动通知其他实例,从而改变其他实例的行为;比如:微服务中的注册中心,当一个服务下线之后,注册中心就会通知其他关联的服务,让其他模块不再调用这个已经下线的模块了。

  • 「中介者模式(Mediator)」

    定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。

  • 「迭代器模式(Iterator)」

    提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

  • 「访问者模式(Visitor)」

    在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。

  • 「备忘录模式(Memento)」

    在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。

  • 「解释器模式(Interpreter)」

    提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

如何学好设计模式呢?

  1. 「多看」

    何为多看?学习设计模式并不像用某个框架那么简单,会使用某个API就好了;

    他是需要一个闭关修炼的过程,多看、多想、多思考。

    多看优秀的框架代码,多想想优秀的框架对设计模式的运用,然后再结合自己的业务去思考,如何运用的自己的业务开发中来。

  2. 「多写」

    脑子说:我会了!

    手说:你不对!

    这也是经常会遇到的一种情况;人的大脑是有「浅记忆」「深度记忆」的,当你去看别人写的代码时,形成的只是浅记忆,可能当时记住了,但是过了一段时间就忘记了;

    同时看的过程会忽略某一些细小的细节;看似看明白了,其实并没有真正的理解透彻;只有真正自己动手去写每一行代码的时候,才能发现其中的细节,也才能将理解变成深度记忆并熟练运用。

  3. 「多运用」

    当我们对设计模式使用不熟悉的时候,要尝试着多运用设计模式;通过时间去积累,从而产生质变;

    我想每个程序员都应该有过“顿悟”的经历,突然某一个瞬间的一行代码,让你彻底想明白曾经纠结的好久的问题;那么这就是量变带来的效果。

  4. 「避免过度设计」

    设计模式的初衷是为了提高代码的可复用性可维护性可读性稳健性以及安全性

    但是在使用设计模式的过程中不可避免的会增加代码的复杂度;

    如果你发现一顿“操作”之后,并没有让代码变的简单,反而让他更复杂;加了设计模式之后,带来了得不偿失的效果,那么我劝你就不要加的;很可能你当前做的产品,就不适合使用设计模式;也可能是“邯郸学步”,并没有利用好对的设计模式。

  5. 「谁是最好的设计模式?」

    上面列了那么多设计模式,谁才是最好的设计模式呢?

    其实并没有什么最好的设计模式,只有最合适的设计模式!每种设计模式都会是某个特殊场景下的最佳实践;

    而且,日常使用中,设计模式从来都不会单个模式独立使用,更多的是多个模式相互配合,查缺补漏,你中有我,我中有你,从而达到方案的最优解。

    设计模式之间的关系

对象对象的设计原则

为了能更好的运用设计模式,提高系统的灵活性、扩展性,我们必须遵循以下的7大原则:

  • 开闭原则

  • 里氏替换原则

  • 依赖导致原则

  • 单一职责原则

  • 接口隔离原则

  • 迪米特法则

  • 合成复用原则

到这里,我们对设计模式的重要性、分类、特点、设计原则都有了一定的了解;接下来的一段时间,会将上面说到的点通过详细的代码示例,逐一的进行讲解。

敬请持续关注!


End


最近开发整理了一个用于速刷面试题的小程序;其中收录了上千常见面试题及答案(包含基础并发JVMMySQLRedisSpringSpringMVCSpringBootSpringCloud、消息队列等多个类型),欢迎您的使用。QQ交流群:912509560


-----  推荐阅读  -----
Java生成随机数的5种方法,你都知道吗?
MySQL 5.7和8.0谁的性能更优?
JAVA实现PDF和EXCEL生成、数据动态插入、导出
一文吃透MyBatis-Plus常用API,包教包会

感谢您的点赞在看星标

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存